<template>
  <div class="tm-number" :style="style">
    <span v-if="prefix||$slots.prefix" class="tm-number__prefix" :style="prefixStyle">
      <slot name="prefix">{{prefix}}</slot>
    </span>
    <span class="tm-number_value" ref="container">
      <slot :value="value" :displayValue="displayValue">{{displayValue}}</slot>
    </span>
    <span v-if="suffix||$slots.suffix" class="tm-number__suffix" :style="suffixStyle">
      <slot name="suffix">{{suffix}}</slot>
    </span>
  </div>
</template>

<script>
import CountUp from './CountUp'

const defaultCountUp = {
  auto: true, // 是否自动开始计数，默认为自动开始
  startVal: 0, // 计数初始值，不限正负数，默认值为0
  decimalPlaces: 0, // 计数器数值精度。默认值为0
  duration: 2, // 计数器动画持续时间，即计数器从开始到结束的时间，单位为秒，默认值为2秒
  useEasing: true, // 是否显示渐入渐出效果。默认值为显示
  useGrouping: true, // 计数器是否采用带格式的值，如10,000和10000两种格式（分隔符用separator来定义），默认值为使用
  separator: ',' // 分隔值的符号，默认值为‘,’（英文逗号）
}

export default {
  name: 'tm-number',
  cnName: '数字',
  mixins: [CountUp],
  props: {
    // 数字
    value: [Number, String],
    // 默认值
    defaultValue: {
      type: [Number, String],
      default: 0
    },
    // CountUp配置参数对象
    countUp: {
      type: [Boolean, Object]
    },
    // 趋势
    trend: {
      type: String,
      validator(val) {
        return ['up', 'down', '-'].includes(val)
      }
    },
    // 精度，保留几位小数
    precision: {
      type: Number,
      default: 0
    },
    // 分隔符
    separator: {
      type: String,
      default: ','
    },
    // 前缀
    prefix: {
      type: String
    },
    // 后缀
    suffix: String,

    // 按百分比计算显示
    percentage: Boolean
  },
  data() {
    return {}
  },
  methods: {
    isNumber(n) {
      const val = Number.parseFloat(n)
      return !Number.isNaN(val) && Number.isFinite(val)
    },
    getPercent(val) {
      return this.percentage
          ? `${(Number.parseFloat(val) * 100).toFixed(this.precision)}%`
          : val
    },
    /**
     * 数字显示分隔符
     * @param val
     * @param n
     * @param separator
     * @return {string}
     */
    format(val, n, separator) {
      const s = Number.parseFloat(String(val).replace(/[^\d.-]/g, '')).toFixed(n) + '';
      const l = s.split('.')[0].split('').reverse()
      const r = s.split('.')[1]
      let t = ''
      for (let i = 0; i < l.length; i++) {
        t += l[i] + ((i + 1) % 3 === 0 && (i + 1) !== l.length ? `${separator}` : '');
      }
      return t.split('').reverse().join('') + (r ? `.${r}` : '')
    }
  },
  computed: {
    style() {
      const style = {
        color: this.$attrs.color,
        fontSize: `${this.$attrs.fontSize}px`,
        fontWeight: this.$attrs.fontWeight,
        fontStyle: this.$attrs.fontStyle,
        fontFamily: this.$attrs.fontFamily
      }

      if(this.$attrs.isShadow) {
        style.textShadow = `${this.$attrs.shadowOffsetX}px ${this.$attrs.shadowOffsetY}px ${this.$attrs.shadowBlur}px ${this.$attrs.shadowColor}`
      }

      return style
    },
    prefixStyle() {
      return {
        color: this.$attrs.prefixColor,
        fontSize: `${this.$attrs.prefixSize}px`
      }
    },
    suffixStyle() {
      return {
        color: this.$attrs.suffixColor,
        fontSize: `${this.$attrs.suffixSize}px`
      }
    },
    displayValue() {
      if (!this.isNumber(this.value)) {
        return this.defaultValue ? this.getPercent(this.defaultValue) : ''
      }

      if (this.percentage) {
        return this.getPercent(this.value)
      }

      return this.format(this.value, this.precision, this.separator)
    },
    trendIcon() {
      if (!this.trend) return null
      const classes = {
        up: 'el-icon-top',
        down: 'el-icon-bottom',
        '-': 'el-icon-minus'
      }
      return classes[this.trend]
    },
    trendClasses() {
      if (!this.trend) return
      if (this.trend === '-') {
        return 'is-default'
      }
      return `is-${this.trend}`
    },
    classes() {
      return {
        'my-number': true,
        'is-pointer': this.$listeners.click,
        [`is-${this.type}`]: !!this.type
      }
    },
    countUpOptions() {
      if (!this.countUp) return null
      return {
        ...defaultCountUp,
        ...this.countUp,
        separator: this.separator,
        decimalPlaces: this.precision
      }
    }
  }
}
</script>

<style lang="less" scoped>
.tm-number {
  display: inline-block;

  &>span {
    vertical-align: baseline
  }
}
</style>
